import { Service } from 'egg';
import { Paint } from '../model/Paint';
import { PaintValue } from '../model/Paint_values';
import { UserPaint } from '../model/User_paint';

class PaintService extends Service {
    /**
     * 查询画像设置列表
     */
    public async searchPaintList() {
        const paintList = await this.ctx.model.Paint.findAll({
            attributes: ['paint_id', 'paint_title', 'paint_order', 'paint_question', 'paint_type'
                , 'paint_selected_count', 'paint_color', 'paint_status'], order: [['paint_order', 'ASC']]
        });
        if (paintList.length <= 0) {
            throw new Error(JSON.stringify({ code: 2, msg: '没有数据' }));
        }
        return paintList;
    }

    /**
     * 创建画像
     * @param param 
     */
    public async createPaint(paint: any, paintValueList: any) {
        paint.paint_id = this.ctx.helper.genUUID();//创建id
        paint.paint_status = '1';//状态默认为正常
        paint.paint_order = (await this.ctx.model.Paint.count()) + 1;//序号默认排在最后
        const tran = await this.ctx.model.transaction();//创建事务
        for (let i = 0; i < paintValueList.length; i++) {
            paintValueList[i]['paint_value_id'] = this.ctx.helper.genUUID();
            paintValueList[i]['paint_id'] = paint.paint_id;
            paintValueList[i]['paint_value_type'] = '1';//画像类型
            paintValueList[i]['paint_value_order'] = i + 1;
            paintValueList[i]['paint_value_status'] = '1';
            paintValueList[i]['is_delete'] = '1';
        }
        try {
            await this.ctx.model.Paint.create(paint, { transaction: tran });
            if (paintValueList.length > 0) {
                await this.ctx.model.PaintValues.bulkCreate(paintValueList, { transaction: tran });
            }
            await tran.commit();
        } catch (e) {
            await tran.rollback();
            this.ctx.logger.error(e);
            throw new Error(JSON.stringify({ code: 2, msg: '添加失败' }));
        }

    }

    /**
     * 启用、停用画像
     * @param type 
     * @param paint_id 
     */
    public async startAndStopPaint(type: number, paint_id: string) {
        const result = await this.ctx.model.Paint.update({ paint_status: type }, { where: { paint_id } });
        if (result[0] <= 0) {
            throw new Error(JSON.stringify({ code: 2, msg: '操作失败' }));
        }
        return result;
    }

    /**
     * 上移、下移画像
     * @param paint_id 
     * @param paint_order 
     * @param type 
     */
    public async removePaint(paint_id: string, paint_order: number, type: number) {
        let allCount = await this.ctx.model.Paint.count();
        if (type === 1 && paint_order === 1) {
            throw new Error(JSON.stringify({ code: 2, msg: '已到达顶部，不能上移' }));
        } else if (type === 2 && paint_order === allCount) {
            throw new Error(JSON.stringify({ code: 2, msg: '已到达低部，不能下移' }));
        }
        let changOrder: number = -1;
        if (type === 1) {
            changOrder = paint_order - 1;
        } else if (type === 2) {
            changOrder = paint_order + 1;
        }
        const checkPaint = await this.ctx.model.Paint.findOne<Paint>({ where: { paint_id, paint_order } });
        if (!checkPaint) {
            throw new Error(JSON.stringify({ code: 2, msg: '未找到当前操作的画像' }));
        }
        const targetPaint: any = await this.ctx.model.Paint.findOne<Paint>({ attributes: ['paint_id'], where: { paint_order: changOrder } });
        const targetPaintId = targetPaint['paint_id'];
        if (!targetPaintId) {
            throw new Error(JSON.stringify({ code: 2, msg: '未能找到目标画像' }));
        }
        const tran = await this.ctx.model.transaction();
        try {
            const resultData = await this.ctx.model.Paint.update({ paint_order: paint_order }, { transaction: tran, where: { paint_id: targetPaintId } });
            const resultData1 = await this.ctx.model.Paint.update({ paint_order: changOrder }, { transaction: tran, where: { paint_id: paint_id } });
            if (resultData[0] <= 0 || resultData1[0] <= 0) {
                throw new Error('移动失败');
            }
            tran.commit();
        } catch (e) {
            await tran.rollback();
            this.ctx.logger.error(e);
            throw new Error(JSON.stringify({ code: 2, msg: '移动失败' }));
        }

    }

    /**
     * 根据id查找画像
     * @param paint_id 
     */
    public async searchPaintById(paint_id: string) {
        const resultPaint: any = await this.ctx.model.Paint.findOne<Paint>({
            attributes: ['paint_id', 'paint_title', 'paint_question', 'paint_selected_count', 'paint_type', 'paint_color'],
            where: { paint_id },
        });
        if (!resultPaint) {
            throw new Error(JSON.stringify({ code: 2, msg: '查询失败' }));
        }
        return resultPaint;
    }

    /**
     * 根据id查找画像值列表
     * @param paint_id 
     */
    public async searchPaintValueById(paint_id: string) {
        const resultPaintValue = await this.ctx.model.PaintValues.findAll<PaintValue>({
            attributes: ['paint_value_id', 'paint_id', 'paint_value_order', 'paint_value_title', 'paint_value_type'],
            where: { paint_id, is_delete: '1' },
            order: [['paint_value_order', 'ASC']]
        });
        if (resultPaintValue.length <= 0) {
            throw new Error(JSON.stringify({ code: 1, msg: '没有数据' }));
        }
        return resultPaintValue;
    }

    /**
     * 修改画像设置
     * @param paint_id 
     * @param param 
     */
    public async updatePaint(param: {}) {
        const paint_id = param['paint_id'];
        const paintValue: any = {};
        paintValue.paint_title = param['paint_title'];
        paintValue.paint_selected_count = Number(param['paint_selected_count']);
        paintValue.paint_question = param['paint_question'];
        paintValue.paint_type = param['paint_type'];
        paintValue.paint_color = param['paint_color'];
        const resultPaint = await this.ctx.model.Paint.update(paintValue, { where: { paint_id } });
        if (resultPaint[0] <= 0) {
            throw new Error(JSON.stringify({ code: 2, msg: '更新失败' }));
        }
    }

    /**
     * 添加画像值
     * @param param 
     */
    public async createPaintValue(param: {}) {
        let submitData: any = {};
        submitData.paint_value_id = this.ctx.helper.genUUID();//生成id
        submitData.paint_id = param['paint_id'];
        submitData.paint_value_title = param['paint_value_title'];
        submitData.paint_value_order = (await this.ctx.model.PaintValues.count({ where: { paint_id: param['paint_id'], is_delete: '1' } })) + 1;
        submitData.paint_value_type = '1';
        submitData.paint_value_status = '1';
        submitData.is_delete = '1';
        const resultPaintValue = await this.ctx.model.PaintValues.create(submitData);
        if (!resultPaintValue) {
            throw new Error(JSON.stringify({ code: 2, msg: '添加失败' }));
        }
    }

    /**
     * 删除画像值
     * @param param 
     */
    public async deletePaintValue(param: {}) {
        const model = this.ctx.model;
        const paint_value_order = Number(param['paint_value_order']);
        const allCount = await model.PaintValues.count({ where: { paint_id: param['paint_id'], is_delete: '1' } });
        const tran = await this.ctx.model.transaction();
        if (paint_value_order === allCount) {
            try {
                await model.PaintValues.update(
                    { is_delete: '2' },
                    { where: { paint_id: param['paint_id'], paint_value_id: param['paint_value_id'] }, transaction: tran }
                );
                await model.UserPaint.update({ is_delete: '2' }, { where: { paint_value_id: param['paint_value_id'] }, transaction: tran });
                await tran.commit();
            } catch (e) {
                await tran.rollback();
                this.ctx.logger.error(e);
                throw new Error(JSON.stringify({ code: 2, msg: '删除失败' }));
            }
        } else if (paint_value_order < allCount) {
            const Op = this.ctx.model.Op;
            const resultPaintValue: any = await model.PaintValues.findAll<PaintValue>({
                attributes: ['paint_value_id', 'paint_value_order'],
                where: {
                    paint_id: param['paint_id'],
                    is_delete: '1',
                    paint_value_order: { [Op.gt]: param['paint_value_order'] },
                },
            });
            try {
                await model.PaintValues.update(
                    { is_delete: '2' },
                    { where: { paint_id: param['paint_id'], paint_value_id: param['paint_value_id'] }, transaction: tran }
                );
                await model.UserPaint.update({ is_delete: '2' }, { where: { paint_value_id: param['paint_value_id'] }, transaction: tran });
                for (let i = 0; i < resultPaintValue.length; i++) {
                    resultPaintValue[i].paint_value_order -= 1;
                    await this.ctx.model.PaintValues.update(
                        { paint_value_order: resultPaintValue[i].paint_value_order },
                        { where: { paint_value_id: resultPaintValue[i].paint_value_id }, transaction: tran },
                    )
                }
                await tran.commit();
            } catch (e) {
                await tran.rollback();
                this.ctx.logger.error(e);
                throw new Error(JSON.stringify({ code: 2, msg: '删除失败' }));
            }
        }
    }

    /**
     * 上移、下移画像值
     * @param param 
     */
    public async removePaintValue(paint_id: string, paint_value_id: string, paint_value_order: number, type: number) {
        let allCount = await this.ctx.model.PaintValues.count({ where: { is_delete: '1', paint_id } });
        if (type === 1 && paint_value_order === 1) {//判断序号是否为1且操作类型为上移
            throw new Error(JSON.stringify({ code: 2, msg: '已到达顶部，不能上移' }));
        } else if (type === 2 && paint_value_order === allCount) {//判断序号是否等于数据总数且操作类型为下移
            throw new Error(JSON.stringify({ code: 2, msg: '已到达低部，不能下移' }));
        }
        let changOrder: number = -1;
        if (type === 1) {
            changOrder = paint_value_order - 1;
        } else if (type === 2) {
            changOrder = paint_value_order + 1;
        }
        const paintValue = await this.ctx.model.PaintValues.findOne<PaintValue>({ where: { paint_value_id, paint_id, paint_value_order } });
        if (!paintValue) {
            throw new Error(JSON.stringify({ code: 2, msg: '找不到该画像值' }));
        }
        const tran = await this.ctx.model.transaction();
        try {
            const targetPaintValue: any = await this.ctx.model.PaintValues.findOne<PaintValue>({ attributes: ['paint_value_id'], where: { paint_value_order: changOrder, paint_id } });
            const targetPaintId = targetPaintValue['paint_value_id'];
            const reusltData = await this.ctx.model.PaintValues.update({ paint_value_order: paint_value_order }, { transaction: tran, where: { paint_value_id: targetPaintId, paint_id } });
            const reusltData1 = await this.ctx.model.PaintValues.update({ paint_value_order: changOrder }, { transaction: tran, where: { paint_value_id, paint_id } });
            if (reusltData[0] <= 0 || reusltData1[0] <= 0) {
                throw new Error('移动失败');
            }
            tran.commit();
        } catch (e) {
            await tran.rollback();
            this.ctx.logger.error(e);
            throw new Error(JSON.stringify({ code: 2, msg: '移动失败' }));
        }
    }

    /**
     * 查找画像及画像值
     */
    public async searchPaintAndValue() {
        const resultPaint: any = await this.ctx.model.Paint.findAll<Paint>({
            attributes: ['paint_id', 'paint_title', 'paint_order', 'paint_question', 'paint_type', 'paint_selected_count', 'paint_color'],
            where: { paint_status: '1' },
            order: [['paint_order', 'ASC']]
        });
        let returnData: any = [];
        for (let i = 0; i < resultPaint.length; i++) {
            let item: any = {};
            item.paint_id = resultPaint[i]['paint_id'];
            item.paint_title = resultPaint[i]['paint_title'];
            item.paint_order = resultPaint[i]['paint_order'];
            item.paint_question = resultPaint[i]['paint_question'];
            item.paint_type = resultPaint[i]['paint_type'];
            item.paint_selected_count = resultPaint[i]['paint_selected_count'];
            item.paint_color = resultPaint[i]['paint_color'];
            const resultPaintValue = await this.ctx.model.PaintValues.findAll<PaintValue>({
                attributes: ['paint_value_id', 'paint_value_title'],
                where: { paint_id: item.paint_id, is_delete: '1', paint_value_status: '1' },
                order: [['paint_value_order', 'ASC']]
            });
            item.paint_value = resultPaintValue;
            returnData.push(item);
        }
        return returnData;
    }
    /**
     * 根据用户id查找画像值
     * @param param 
     */
    public async searchPaintValueByUserId(param: any) {
        const queryStr = `SELECT up.paint_id,p.paint_type,GROUP_CONCAT(up.paint_value_id) as paint_value_id,up.paint_value FROM t_user_paint up inner join t_paint p on up.paint_id=p.paint_id and p.paint_status='1'`
            + ` WHERE up.user_id=:user_id and up.is_delete='1' GROUP BY up.paint_id `;
        const result = await this.ctx.model.query(
            queryStr,
            {
                type: this.ctx.model.QueryTypes.SELECT,
                replacements: { user_id: param.user_id }
            }
        );
        if (result.length <= 0) {
            throw new Error(JSON.stringify({ code: 2, msg: '没有数据' }));
        }
        return result;
    }
    /**
     * 修改用户画像值
     */
    public async updateUserPaintValue(param: any) {
        const type = param.paint_type;
        if (type == 1) {
            let paint_value: any = [];
            if (param.paint_value && param.paint_value.length > 0) {
                paint_value = param.paint_value.split(',');
            }
            const tran = await this.ctx.model.transaction();
            try {
                await this.ctx.model.UserPaint.destroy({ where: { user_id: param.user_id, paint_id: param.paint_id }, transaction: tran });
                if (paint_value.length > 0) {
                    for (let i = 0; i < paint_value.length; i++) {
                        let submitData = new UserPaint();
                        submitData.user_paint_id = this.ctx.helper.genUUID();
                        submitData.user_id = param.user_id;
                        submitData.paint_value_id = paint_value[i];
                        submitData.paint_id = param.paint_id;
                        submitData.is_delete = '1';
                        await this.ctx.model.UserPaint.create(submitData, { transaction: tran });
                    }
                }
                await this.computePaint(param, tran);
                await tran.commit();
            } catch (e) {
                await tran.rollback();
                this.ctx.logger.error(e);
                throw new Error(JSON.stringify({ code: 2, msg: '更新失败' }));
            }
        } else if (type == 2) {
            const user_id = param.user_id;
            const paint_id = param.paint_id;
            const paint_value = param.paint_value;
            const tran = await this.ctx.model.transaction();
            try {
                await this.ctx.model.UserPaint.destroy({ where: { user_id: param.user_id, paint_id: param.paint_id }, transaction: tran });
                if (paint_value && paint_value.length > 0) {
                    const submitData: any = {};
                    submitData.user_paint_id = this.ctx.helper.genUUID();
                    submitData.user_id = user_id;
                    submitData.paint_value_id = '';
                    submitData.paint_id = paint_id;
                    submitData.paint_value = paint_value;
                    submitData.is_delete = '1';
                    const resultCreate = await this.ctx.model.UserPaint.create(submitData, { transaction: tran });
                    if (!resultCreate) {
                        throw new Error(JSON.stringify({ code: 2, msg: '更新失败' }));
                    }
                }
                await this.computePaint(param, tran);
                await tran.commit();
            } catch (e) {
                await tran.rollback();
                this.ctx.logger.error(e);
                throw new Error(JSON.stringify({ code: 2, msg: '更新失败' }));
            }
        }
    }

    public async computePaint(param: any, tran: any) {
        const resultPaint = await this.ctx.model.Paint.count({ where: { paint_status: '1' }, transaction: tran });
        const queryStr = `
                    SELECT
                        * 
                    FROM
                        (
                        (
                    SELECT
                        u.paint_id 
                    FROM
                        t_user_paint u
                        INNER JOIN t_paint p ON u.paint_id = p.paint_id 
                        AND p.paint_status = '1'
                        INNER JOIN t_paint_value v ON u.paint_value_id = v.paint_value_id 
                        AND v.is_delete = '1' 
                        AND v.paint_value_status = '1' 
                    WHERE
                        u.is_delete = '1' 
                        AND u.user_id = :user_id
                    GROUP BY
                        u.paint_id 
                        ) UNION
                        (
                    SELECT
                        u.paint_id 
                    FROM
                        t_user_paint u
                        INNER JOIN t_paint p ON u.paint_id = p.paint_id 
                        AND p.paint_status = '1' 
                    WHERE
                        u.is_delete = '1' 
                        AND u.user_id = :user_id
                        AND (u.paint_value_id IS NULL 
                        OR u.paint_value_id = '') 
                    GROUP BY
                        u.paint_id 
                        ) 
                        ) temp`;
        const resultUserPaint: any = await this.ctx.model.query(queryStr, {
            type: this.ctx.model.QueryTypes.SELECT,
            replacements: { user_id: param.user_id },
            transaction: tran
        })
        const count = resultUserPaint.length;
        const result = (count / resultPaint * 100).toString();
        const user_finish = Number(result.split('.')[0]);
        await this.ctx.model.User.update({ user_finish }, { where: { user_id: param.user_id }, transaction: tran });
    }

}
export default PaintService;